這篇文章,主要是設計給我自己要用的 Video Player 畫 ROI 工具。
所以很多功能都是替我自己客製化。
https://github.com/howarder3/ironman2021_PyQt5_photoshop/tree/main/day27_video_roi_project
我們接下來的討論,會基於讀者已經先讀過我 day5 文章 的架構下去進行程式設計
如果還不清楚我程式設計的邏輯 (UI.py、controller.py、start.py 分別在幹麻)
建議先閱讀 day5 文章後再來閱讀此文。
https://www.wongwonggoods.com/python/pyqt5-5/
這篇文章由於是我在撰寫 day25 的時候另外寫的,還沒有做出 day26 的優化更新,
如果有興趣的可以自己再改,這邊只專注在講新增的功能
主要就是新增滑條的部分,新元素的名稱:
pyuic5 -x day27.ui -o UI.py
一樣,這程式只有介面 (視覺上的呈現),沒有任何互動功能
python UI.py
連結這兩個按鍵至兩個對應的 function
def set_video_player(self):
    self.ui.button_clear_points.clicked.connect(self.clear_points)
    self.ui.button_generate_rois.clicked.connect(self.generate_rois)
按下按鍵後,就要進行對應的文字更新,
def clear_points(self):
    self.list_collect_points = []
    self.__update_text_show_points()
def __update_text_show_points(self):
    msg = "Current points (right click to return origin):\n"
    for ele in self.list_collect_points:
        msg += f"({ele[0]},{ele[1]})\n"
    self.ui.text_save_points.setText(msg)
	
def generate_rois(self):
    msg = "[\n"
    for ele in self.list_collect_points:
        msg += f"[{ele[0]},{ele[1]}],\n"
    msg += "]"
    self.ui.text_output_rois.setText(msg)
替我們的 Qlabel 定義一個按鍵 function,
偵測 Qlabel 上的滑鼠點擊事件,並儲存座標進 self.list_collect_points 裡面。
新增點之後,更新點至顯示畫面。
def mouse_press_event(self, event):
    print(f"[show_mouse_press] {event.x()=}, {event.y()=}, {event.button()=}")
    norm_x = event.x()/self.qpixmap.width()
    norm_y = event.y()/self.qpixmap.height()
    if event.button() == 2: # right clicked
        self.list_collect_points.append(self.list_collect_points[0])
        self.__update_text_show_points()
def __update_points_onscreen(self, frame):
    if len(self.list_collect_points) == 0:
        pass
    else: # len(list) >= 1
        # first points
        frame = opencv_engine.draw_point(frame, point=self.list_collect_points[0], color = (0, 0, 255)) # red
        # if len = 1, no lines
        for idx in range(1, len(self.list_collect_points)):
            frame = opencv_engine.draw_point(frame, point=self.list_collect_points[idx], color = (0, 0, 255)) # red
            frame = opencv_engine.draw_line(frame, start_point =self.list_collect_points[idx-1], end_point=self.list_collect_points[idx], color = (0, 255, 0)) # green
    return frame
class opencv_engine(object):
    @staticmethod
    def norm_point_to_int(img, point):
        img_height, img_width, img_channel = img.shape
        return (int(img_width*point[0]), int(img_height*point[1]))
    @staticmethod
    def draw_point(img, point=(0, 0), color = (0, 0, 255)): # red
        point = opencv_engine.norm_point_to_int(img, point)
        # print(f"get {point=}")
        point_size = 10
        thickness = 4
        return cv2.circle(img, point, point_size, color, thickness)
    @staticmethod
    def draw_line(img, start_point = (0, 0), end_point = (0, 0), color = (0, 255, 0)): # green
        start_point = opencv_engine.norm_point_to_int(img, start_point)
        end_point = opencv_engine.norm_point_to_int(img, end_point)
        thickness = 3 # width
        return cv2.line(img, start_point, end_point, color, thickness)
好啦,我自己要用的話 Video Player 畫 ROI 工具就這樣完成了!!!
★ 本文也同步發於我的個人網站(會有內容目錄與顯示各個小節,閱讀起來更流暢):【PyQt5】Day 27 project / 製作影片 ROI 標註工具 (PyQt 結合 OpenCV 在圖上畫點畫線)